home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
edit
/
elv18src.zip
/
input.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-28
|
17KB
|
883 lines
/* input.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains the input() function, which implements vi's INPUT mode.
* It also contains the code that supports digraphs.
*/
#include "config.h"
#include "ctype.h"
#include "vi.h"
#ifndef NO_DIGRAPH
static struct _DIG
{
struct _DIG *next;
char key1;
char key2;
char dig;
char save;
} *digs;
char digraph(key1, key2)
int key1; /* the underlying character */
int key2; /* the second character */
{
int newkey;
REG struct _DIG *dp;
/* if digraphs are disabled, then just return the new char */
if (!*o_digraph)
{
return key2;
}
/* remember the new key, so we can return it if this isn't a digraph */
newkey = key2;
/* sort key1 and key2, so that their original order won't matter */
if (key1 > key2)
{
key2 = key1;
key1 = newkey;
}
/* scan through the digraph chart */
for (dp = digs;
dp && (dp->key1 != key1 || dp->key2 != key2);
dp = dp->next)
{
}
/* if this combination isn't in there, just use the new key */
if (!dp)
{
return newkey;
}
/* else use the digraph key */
return dp->dig;
}
/* this function lists or defines digraphs */
void do_digraph(bang, extra)
int bang;
char extra[];
{
int dig;
REG struct _DIG *dp;
struct _DIG *prev;
static int user_defined = FALSE; /* boolean: are all later digraphs user-defined? */
char listbuf[8];
/* if "extra" is NULL, then we've reached the end of the built-ins */
if (!extra)
{
user_defined = TRUE;
return;
}
/* if no args, then display the existing digraphs */
if (*extra < ' ')
{
listbuf[0] = listbuf[1] = listbuf[2] = listbuf[5] = ' ';
listbuf[7] = '\0';
for (dig = 0, dp = digs; dp; dp = dp->next)
{
if (dp->save || bang)
{
dig += 7;
if (dig >= COLS)
{
addch('\n');
exrefresh();
dig = 7;
}
listbuf[3] = dp->key1;
listbuf[4] = dp->key2;
listbuf[6] = dp->dig;
qaddstr(listbuf);
}
}
addch('\n');
exrefresh();
return;
}
/* make sure we have at least two characters */
if (!extra[1])
{
msg("Digraphs must be composed of two characters");
return;
}
/* sort key1 and key2, so that their original order won't matter */
if (extra[0] > extra[1])
{
dig = extra[0];
extra[0] = extra[1];
extra[1] = dig;
}
/* locate the new digraph character */
for (dig = 2; extra[dig] == ' ' || extra[dig] == '\t'; dig++)
{
}
dig = extra[dig];
if (!bang && dig)
{
dig |= 0x80;
}
/* search for the digraph */
for (prev = (struct _DIG *)0, dp = digs;
dp && (dp->key1 != extra[0] || dp->key2 != extra[1]);
prev = dp, dp = dp->next)
{
}
/* deleting the digraph? */
if (!dig)
{
if (!dp)
{
#ifndef CRUNCH
msg("%c%c not a digraph", extra[0], extra[1]);
#endif
return;
}
if (prev)
prev->next = dp->next;
else
digs = dp->next;
_free_(dp);
return;
}
/* if necessary, create a new digraph struct for the new digraph */
if (dig && !dp)
{
dp = (struct _DIG *)malloc(sizeof *dp);
if (!dp)
{
msg("Out of space in the digraph table");
return;
}
if (prev)
prev->next = dp;
else
digs = dp;
dp->next = (struct _DIG *)0;
}
/* assign it the new digraph value */
dp->key1 = extra[0];
dp->key2 = extra[1];
dp->dig = dig;
dp->save = user_defined;
}
# ifndef NO_MKEXRC
void savedigs(fd)
int fd;
{
static char buf[] = "digraph! XX Y\n";
REG struct _DIG *dp;
for (dp = digs; dp; dp = dp->next)
{
if (dp->save)
{
buf[9] = dp->key1;
buf[10] = dp->key2;
buf[12] = dp->dig;
write(fd, buf, (unsigned)14);
}
}
}
# endif
#endif
/* This function allows the user to replace an existing (possibly zero-length)
* chunk of text with typed-in text. It returns the MARK of the last character
* that the user typed in.
*/
MARK input(from, to, when, delta)
MARK from; /* where to start inserting text */
MARK to; /* extent of text to delete */
int when; /* either WHEN_VIINP or WHEN_VIREP */
int delta; /* 1 to take indent from lower line, -1 for upper, 0 for none */
{
char key[2]; /* key char followed by '\0' char */
char *build; /* used in building a newline+indent string */
char *scan; /* used while looking at the indent chars of a line */
MARK m; /* some place in the text */
#ifndef NO_EXTENSIONS
int quit = FALSE; /* boolean: are we exiting after this? */
int inchg; /* boolean: have we done a "beforedo()" yet? */
#endif
#ifdef DEBUG
/* if "from" and "to" are reversed, complain */
if (from > to)
{
msg("ERROR: input(%ld:%d, %ld:%d)",
markline(from), markidx(from),
markline(to), markidx(to));
return MARK_UNSET;
}
#endif
key[1] = 0;
/* if we're replacing text with new text, save the old stuff */
/* (Alas, there is no easy way to save text for replace mode) */
if (from != to)
{
cut(from, to);
}
/* if doing a dot command, then reuse the previous text */
if (doingdot)
{
ChangeText
{
/* delete the text that's there now */
if (from != to)
{
delete(from, to);
}
/* insert the previous text */
cutname('.');
cursor = paste(from, FALSE, TRUE) + 1L;
}
}
else /* interactive version */
{
/* assume that whoever called this already did a beforedo() */
#ifndef NO_EXTENSIONS
inchg = TRUE;
#endif
/* if doing a change within the line... */
if (from != to && markline(from) == markline(to))
{
/* mark the end of the text with a "$" */
change(to - 1, to, "$");
}
else
{
/* delete the old text right off */
if (from != to)
{
delete(from, to);
}
to = from;
}
/* handle autoindent of the first line, maybe */
cursor = from;
m = cursor + MARK_AT_LINE(delta);
if (delta != 0 && *o_autoindent && markidx(m) == 0
&& markline(m) >= 1L && markline(m) <= nlines)
{
/* Only autoindent blank lines. */
pfetch(markline(cursor));
if (plen == 0)
{
/* Okay, we really want to autoindent */
pfetch(markline(m));
for (scan = ptext, build = tmpblk.c;
*scan == ' ' || *scan == '\t';
)
{
*build++ = *scan++;
}
if (build > tmpblk.c)
{
*build = '\0';
add(cursor, tmpblk.c);
cursor += (int)(build - tmpblk.c);
if (cursor > to)
to = cursor;
}
}
}
/* repeatedly add characters from the user */
for (;;)
{
/* Get a character */
redraw(cursor, TRUE);
#ifdef DEBUG2
msg("cursor=%ld.%d, to=%ld.%d",
markline(cursor), markidx(cursor),
markline(to), markidx(to));
#endif
#ifndef NO_ABBR
pfetch(markline(cursor));
build = ptext;
if (pline == markline(from))
build += markidx(from);
for (scan = ptext + markidx(cursor); --scan >= build && !isspace(*scan); )
{
}
scan++;
key[0] = getabkey(when, ptext, markidx(cursor));
#else
key[0] = getkey(when);
#endif
#ifndef NO_VISIBLE
if (key[0] != ctrl('O') && V_from != MARK_UNSET)
{
msg("Can't modify text during a selection");
beep();
continue;
}
#endif
#ifndef NO_EXTENSIONS
if (key[0] == ctrl('O'))
{
if (inchg)
{
if (cursor < to)
{
delete(cursor, to);
redraw(cursor, TRUE);
}
afterdo();
inchg = FALSE;
}
}
else if (key[0] != ctrl('['))
{
if (!inchg)
{
beforedo(FALSE);
inchg = TRUE;
}
}
#endif
#ifndef CRUNCH
/* if wrapmargin is set & we're past the
* warpmargin, then change the last whitespace
* characters on line into a newline
*/
if (*o_wrapmargin)
{
pfetch(markline(cursor));
if (!ptext[markidx(cursor)]
&& idx2col(cursor, ptext, TRUE) > COLS - (*o_wrapmargin & 0xff))
{
build = tmpblk.c;
*build++ = '\n';
if (*o_autoindent)
{
/* figure out indent for next line */
for (scan = ptext; *scan == ' ' || *scan == '\t'; )
{
*build++ = *scan++;
}
}
*build = '\0';
scan = ptext + plen;
m = cursor & ~(BLKSIZE - 1);
while (ptext < scan)
{
scan--;
if (*scan != ' ' && *scan != '\t')
continue;
/*break up line, and we do autoindent if needed*/
change(m + (int)(scan - ptext), m + (int)(scan - ptext) + 1, tmpblk